package relop;

/**
 * The simplest of all join algorithms: nested loops (see textbook, 3rd edition,
 * section 14.4.1, page 454).
 */ 
public class SimpleJoin extends Iterator {
	Iterator [] my_iter;
	Predicate [] mypred;
	Tuple cur_sat;
  /**
   * Constructs a join, given the left and right iterators and join predicates
   * (relative to the combined schema).
   */
  public SimpleJoin(Iterator left, Iterator right, Predicate... preds) {
    //throw new UnsupportedOperationException("Not implemented");
	  my_iter = new Iterator[2];
	  my_iter[0] = left;
	  my_iter[1] = right;
	  mypred = preds;
	  this.schema = Schema.join(left.schema, right.schema);
	  cur_sat = null;
  }

  /**
   * Gives a one-line explaination of the iterator, repeats the call on any
   * child iterators, and increases the indent depth along the way.
   */
  public void explain(int depth) {
   // throw new UnsupportedOperationException("Not implemented");
	  System.out.println("This Simple Join receive two iterators and simply join them.");
	  System.out.println("Then use the predicates to select all satisfied tuples.");
	  
  }

  /**
   * Restarts the iterator, i.e. as if it were just constructed.
   */
  public void restart() {
  //  throw new UnsupportedOperationException("Not implemented");
	  for(int i = 0; i<my_iter.length; i++)
		  my_iter[i].restart();
	  cur_sat = null;
  }

  /**
   * Returns true if the iterator is open; false otherwise.
   */
  public boolean isOpen() {
  //  throw new UnsupportedOperationException("Not implemented");
	  for(int i = 0; i<my_iter.length; i++){
		  if(my_iter[i].isOpen()==false)
			  return false;
	  }
	  return true;
  }

  /**
   * Closes the iterator, releasing any resources (i.e. pinned pages).
   */
  public void close() {
   // throw new UnsupportedOperationException("Not implemented");
	  for(int i = 0; i<my_iter.length; i++){
		  my_iter[i].close();
	  }
	  cur_sat = null;
  }

  /**
   * Returns true if there are more tuples, false otherwise.
   */
  public boolean hasNext() {
  // throw new UnsupportedOperationException("Not implemented");
	  if(cur_sat!=null)
		  return true;
	  
	  Tuple l_cur;
	  Tuple r_cur;
	  Tuple thistuple;
	  
	  while(my_iter[0].hasNext()){
		  l_cur = my_iter[0].getNext();
		  while(my_iter[1].hasNext()){
			  r_cur = my_iter[1].getNext();
			  thistuple = Tuple.join(l_cur, r_cur, schema);
			  for(int i=0; i<mypred.length; i++){
				  Predicate cur_p = mypred[i];
				  boolean success = cur_p.evaluate(thistuple);
				  if(success==true){
					  cur_sat = thistuple;
					  return true;
				  }
				  else
					  continue;
			  }
		  }		  
	  }
	  return false;
  }

  /**
   * Gets the next tuple in the iteration.
   * 
   * @throws IllegalStateException if no more tuples
   */
  public Tuple getNext() {
   // throw new UnsupportedOperationException("Not implemented");
	  if(cur_sat!=null){
		  Tuple temp = cur_sat;
		  cur_sat = null;
		  return temp;
	  }
	  
	  Tuple l_cur;
	  Tuple r_cur;
	  Tuple thistuple;
	  
	  while(my_iter[0].hasNext()){
		  l_cur = my_iter[0].getNext();
		  while(my_iter[1].hasNext()){
			  r_cur = my_iter[1].getNext();
			  thistuple = Tuple.join(l_cur, r_cur, schema);
			  for(int i=0; i<mypred.length; i++){
				  Predicate cur_p = mypred[i];
				  boolean success = cur_p.evaluate(thistuple);
				  if(success==true){
					  //cur_sat = thistuple;
					  return thistuple;
				  }
				  else
					  continue;
			  }
		  }		  
	  }
	  return null;
  }

} // public class SimpleJoin extends Iterator
